extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/samplefmt.h>
#include "libavutil/opt.h"
#include <SDL.h>
#include <SDL_thread.h>
#include "audio.h"
}

#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif
#include <stdio.h>

#include <android/log.h>
#define JNI_DEBUG
#ifdef JNI_DEBUG
#ifndef LOG_TAG
#define LOG_TAG "JNI_DEBUG"
#endif


#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,  __VA_ARGS__)
#define LOGI(msg) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, msg)
#define LOGD(msg) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, msg)
#endif


//#define SDL_AUDIO_BUFFER_SIZE 1152  
#define SDL_AUDIO_BUFFER_SIZE 1024  
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000  

static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;

int breakPlay = 0;
int isPlaying=0;
const int FF_QUIT_EVENT=357;
char *testc;
int quit = 0;
int checkPlaying(){
	return isPlaying;
}
void stopPlay(){
	isPlaying=0;
	quit=1;
	//SDL_Event event;
	//    event.type =  FF_QUIT_EVENT;
	    //event.user.data1 = is;
	//    SDL_PushEvent(&event);
	//avformat_close_input(&pFormatCtx);
}

void fill_audio(void *udata, Uint8 *stream, int len) {
	if (audio_len == 0)
		return;
	len = (len > audio_len ? audio_len : len);
	SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
	audio_pos += len;
	audio_len -= len;
}

int AudioResampling(AVCodecContext * audio_dec_ctx, AVFrame * pAudioDecodeFrame,
		int out_sample_fmt,
		//AVSampleFormat out_sample_fmt,
		int out_channels, int out_sample_rate, uint8_t* out_buf) {
	SwrContext * swr_ctx = NULL;
	int data_size = 0;
	int ret = 0;
	int64_t src_ch_layout = audio_dec_ctx->channel_layout;
	int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO;
	int dst_nb_channels = 0;
	int dst_linesize = 0;
	int src_nb_samples = 0;
	int dst_nb_samples = 0;
	int max_dst_nb_samples = 0;
	uint8_t **dst_data = NULL;
	int resampled_data_size = 0;

	swr_ctx = swr_alloc();
	if (!swr_ctx) {
		printf("swr_alloc error \n");
		return -1;
	}

	src_ch_layout =
			(audio_dec_ctx->channels
					== av_get_channel_layout_nb_channels(
							audio_dec_ctx->channel_layout)) ?
					audio_dec_ctx->channel_layout :
					av_get_default_channel_layout(audio_dec_ctx->channels);

	if (out_channels == 1) {
		dst_ch_layout = AV_CH_LAYOUT_MONO;
		//printf("dst_ch_layout: AV_CH_LAYOUT_MONO\n");
	} else if (out_channels == 2) {
		dst_ch_layout = AV_CH_LAYOUT_STEREO;
		//printf("dst_ch_layout: AV_CH_LAYOUT_STEREO\n");
	} else {
		dst_ch_layout = AV_CH_LAYOUT_SURROUND;
		//printf("dst_ch_layout: AV_CH_LAYOUT_SURROUND\n");
	}

	if (src_ch_layout <= 0) {
		printf("src_ch_layout error \n");
		return -1;
	}

	src_nb_samples = pAudioDecodeFrame->nb_samples;
	if (src_nb_samples <= 0) {
		printf("src_nb_samples error \n");
		return -1;
	}

	av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
	av_opt_set_int(swr_ctx, "in_sample_rate", audio_dec_ctx->sample_rate, 0);
	av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", audio_dec_ctx->sample_fmt,
			0);

	av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
	av_opt_set_int(swr_ctx, "out_sample_rate", out_sample_rate, 0);
	av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt",
			(AVSampleFormat) out_sample_fmt, 0);

	if ((ret = swr_init(swr_ctx)) < 0) {
		printf("Failed to initialize the resampling context\n");
		return -1;
	}

	max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples,
			out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP);
	if (max_dst_nb_samples <= 0) {
		printf("av_rescale_rnd error \n");
		return -1;
	}

	dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
	ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize,
			dst_nb_channels, dst_nb_samples, (AVSampleFormat) out_sample_fmt,
			0);
	if (ret < 0) {
		printf("av_samples_alloc_array_and_samples error \n");
		return -1;
	}

	dst_nb_samples = av_rescale_rnd(
			swr_get_delay(swr_ctx, audio_dec_ctx->sample_rate) + src_nb_samples,
			out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP);
	if (dst_nb_samples <= 0) {
		printf("av_rescale_rnd error \n");
		return -1;
	}
	if (dst_nb_samples > max_dst_nb_samples) {
		av_free(dst_data[0]);
		ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
				dst_nb_samples, (AVSampleFormat) out_sample_fmt, 1);
		max_dst_nb_samples = dst_nb_samples;
	}

	if (swr_ctx) {
		ret = swr_convert(swr_ctx, dst_data, dst_nb_samples,
				(const uint8_t **) pAudioDecodeFrame->data,
				pAudioDecodeFrame->nb_samples);
		if (ret < 0) {
			printf("swr_convert error \n");
			return -1;
		}

		resampled_data_size = av_samples_get_buffer_size(&dst_linesize,
				dst_nb_channels, ret, (AVSampleFormat) out_sample_fmt, 1);
		if (resampled_data_size < 0) {
			printf("av_samples_get_buffer_size error \n");
			return -1;
		}
	} else {
		printf("swr_ctx null error \n");
		return -1;
	}

	memcpy(out_buf, dst_data[0], resampled_data_size);

	if (dst_data) {
		av_freep(&dst_data[0]);
	}
	av_freep(&dst_data);
	dst_data = NULL;

	if (swr_ctx) {
		swr_free(&swr_ctx);
	}
	return resampled_data_size;
}

typedef struct PacketQueue {
	AVPacketList *first_pkt, *last_pkt;
	int nb_packets;
	int size;
	SDL_mutex *mutex;
	SDL_cond *cond;
} PacketQueue;

PacketQueue audioq;

void packet_queue_init(PacketQueue *q) {
	memset(q, 0, sizeof(PacketQueue));
	q->mutex = SDL_CreateMutex();
	q->cond = SDL_CreateCond();
}
int packet_queue_put(PacketQueue *q, AVPacket *pkt) {

	AVPacketList *pkt1;
	if (av_dup_packet(pkt) < 0) {
		return -1;
	}
	pkt1 = (AVPacketList *) av_malloc(sizeof(AVPacketList));
	if (!pkt1)
		return -1;
	pkt1->pkt = *pkt;
	pkt1->next = NULL;

	SDL_LockMutex(q->mutex);

	if (!q->last_pkt)
		q->first_pkt = pkt1;
	else
		q->last_pkt->next = pkt1;
	q->last_pkt = pkt1;
	q->nb_packets++;
	q->size += pkt1->pkt.size;
	SDL_CondSignal(q->cond);

	SDL_UnlockMutex(q->mutex);
	return 0;
}

int decode_interrupt_cb(void) {
	return quit;
}

static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) {
	AVPacketList *pkt1;
	int ret;

	SDL_LockMutex(q->mutex);

	for (;;) {

		if (quit) {
			ret = -1;
			break;
		}

		pkt1 = q->first_pkt;
		if (pkt1) {
			q->first_pkt = pkt1->next;
			if (!q->first_pkt)
				q->last_pkt = NULL;
			q->nb_packets--;
			q->size -= pkt1->pkt.size;
			*pkt = pkt1->pkt;
			av_free(pkt1);
			ret = 1;
			break;
		} else if (!block) {
			ret = 0;
			break;
		} else {
			SDL_CondWait(q->cond, q->mutex);
		}
	}
	SDL_UnlockMutex(q->mutex);
	return ret;
}

int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf,
		int buf_size) {
	static AVPacket pkt;
	static uint8_t *audio_pkt_data = NULL;
	static int audio_pkt_size = 0;

	int len1, data_size, ret = 0;

	static AVFrame *pFrame;
	pFrame = av_frame_alloc();
	for (;;) {
		while (audio_pkt_size > 0) {
			data_size = buf_size;
			len1 = avcodec_decode_audio4(aCodecCtx, pFrame, &ret, &pkt);

			if (len1 < 0) { //if error, skip frame
				LOGE("error\n");
				audio_pkt_size = 0;
				break;
			}
			data_size = AudioResampling(aCodecCtx, pFrame, AV_SAMPLE_FMT_S16,
					aCodecCtx->channels, aCodecCtx->sample_rate, audio_buf);
			audio_pkt_data += len1;
			audio_pkt_size -= len1;
			if (data_size <= 0) //No data yet, get more frames
				continue;
			return data_size;
		}
		if (pkt.data)
			av_free_packet(&pkt);
		if (quit)
			return -1;
		if (packet_queue_get(&audioq, &pkt, 1) < 0) { //从这里开始，取得main线程放入队列的包
			LOGE("error, can't get packet from the queue");
			return -1;
		}
		audio_pkt_data = pkt.data;
		audio_pkt_size = pkt.size;
	}
}

void audio_callback(void *userdata, Uint8 *stream, int len) {
	//SDL_memset(stream, 0, len);
	AVCodecContext *aCodecCtx = (AVCodecContext*) userdata;
	int len1, audio_size;

	//audio_buf 的大小为 1.5 倍的声音帧的大小以便于有一个比较好的缓冲
	static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
	static unsigned int audio_buf_size = 0;
	static unsigned int audio_buf_index = 0;

	while (len > 0) {
		if (audio_buf_index >= audio_buf_size) { //already send all our data, get more
			audio_size = audio_decode_frame(aCodecCtx, audio_buf,
					sizeof(audio_buf));
			if (audio_size < 0) { //error, output silence
				LOGE("error, output silence\n");
				audio_buf_size = SDL_AUDIO_BUFFER_SIZE;
				memset(audio_buf, 0, audio_buf_size);
			} else
				audio_buf_size = audio_size;
			audio_buf_index = 0;
		}
		len1 = audio_buf_size - audio_buf_index;
		if (len1 > len) {
			len1 = len;
		}
		memcpy(stream, (uint8_t *) audio_buf + audio_buf_index, len1);
		len -= len1;
		stream += len1;
		audio_buf_index += len1;
	}
	if (audioq.nb_packets == 0) {
		breakPlay = 0;
	}
}

int main(int argc, char *argv[]) {
	AVFormatContext *pFormatCtx = NULL;
	int i, audioStream;
	int frameFinished;

	AVCodecContext *aCodecCtx = NULL;
	AVCodec *aCodec = NULL;

	SDL_Event event;
	SDL_AudioSpec wanted_spec, spec;

	AVPacket packet;
	AVDictionary *optionsDict = NULL;

	//char filename[] = "/mnt/sdcard/minzu.mp4";
	//char filename[] = "mmsh://alive.rbc.cn/am774";
	char *filename;
	filename= argv[1];
	quit=0;
	/*if(argc < 2) {
	 fprintf(stderr, "Usage: test <file>\n");
	 exit(1);
	 }*/
	LOGE("%s",filename);
// Register all formats and codecs
	av_register_all();
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
		LOGE( "Could not initialize SDL - %s\n", SDL_GetError());
		isPlaying=0;
		exit(1);
	}
//AVFormatContext *pFormatCtx;  
	pFormatCtx = avformat_alloc_context();
	avcodec_register_all();
	avformat_network_init();
	av_dict_set(&optionsDict, "rtsp_transport", "tcp", 0);
//optionsDict=GetFFMpegOptionsFromURL(filename);
	if (avformat_open_input(&pFormatCtx, filename, NULL, &optionsDict) != 0)

// Open video file
//if(avformat_open_input(&pFormatCtx, filename, NULL, &avdic)!=0)
		return -1; // Couldn't open file

// Retrieve stream information
	if (av_find_stream_info(pFormatCtx) < 0)
		return -1; // Couldn't find stream information

// Dump information about file onto standard error
//dump_format(pFormatCtx, 0, argv[1], 0);
	av_dump_format(pFormatCtx, 0, filename, 0);

// Find the first video stream
	audioStream = -1;
	for (i = 0; i < pFormatCtx->nb_streams; i++) {
		if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO
				&& audioStream < 0) {
			audioStream = i;
		}
	}
	if (audioStream == -1)
		return -1;

	aCodecCtx = pFormatCtx->streams[audioStream]->codec;
// Set audio settings from codec info
	wanted_spec.freq = aCodecCtx->sample_rate;
	wanted_spec.format = AUDIO_S16SYS;
	wanted_spec.channels = aCodecCtx->channels;
	wanted_spec.silence = 0;
	wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
	wanted_spec.callback = audio_callback;
	wanted_spec.userdata = aCodecCtx;
	if (isPlaying==1){
		return 0;
	}

	//if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
	if (SDL_OpenAudio(&wanted_spec, NULL) < 0) {
		LOGE( "SDL_OpenAudio: %s\n", SDL_GetError());
	    SDL_CloseAudioDevice(1);
		SDL_CloseAudio();
		return -1;
	}
	LOGI("This is a logcat test.");

	aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
	if (!aCodec) {
		LOGE( "Unsupported codec!\n");
		return -1;
	}
//avcodec_open(aCodecCtx, aCodec);
	avcodec_open2(aCodecCtx, aCodec, &optionsDict);

// audio_st = pFormatCtx->streams[index]
	packet_queue_init(&audioq);
	SDL_PauseAudio(0);

// Read frames and save first five frames to disk
	i = 0;
	//testc=(char*)malloc(1024);
	//av_read_frame(pFormatCtx, &packet);
	//packet_queue_put(&audioq, &packet);
	//SDL_Delay(4000);
	//goto exit;
	isPlaying=1;
	while (av_read_frame(pFormatCtx, &packet) >= 0) {
		if (packet.stream_index == audioStream) {
			packet_queue_put(&audioq, &packet);
		} else {
			av_free_packet(&packet);
		}

		//使用SDL_event将使java vm产生异常
		/*SDL_PollEvent(&event);
		switch (event.type) {
		case SDL_QUIT:
			SDL_Quit();
			exit(0);
			break;
		case FF_QUIT_EVENT:
			quit = 1;
			LOGE("FF_QUIT_EVENT");
			//av_free_packet(&packet);
			//SDL_CloseAudio();
			//breakPlay=1;
			break;
		default:
			break;
		}
		if (event.type==FF_QUIT_EVENT){
			LOGE("FF_QUIT_EVENT,breaking");
			break;
		}*/
		if (quit==1){
			LOGE("i'm quitting.");
			break;
		}

	}
exit:
LOGE("label:exit");
	/*while (breakPlay==0) {
		SDL_PollEvent(&event);
		switch (event.type) {
		case SDL_QUIT:
			SDL_Quit();
			exit(0);
			break;
		case FF_QUIT_EVENT:
			quit = 1;
			SDL_CloseAudio();
			breakPlay=1;
			break;
		default:
			break;
		}
		if (quit==1){
			LOGE("i'm quitting.");
			break;
		}
		SDL_Delay(40);
	}*/
// Close the video file
	//quit = 1;
	SDL_CloseAudio();
    SDL_CloseAudioDevice(1);
    avformat_close_input(&pFormatCtx);
	av_close_input_file(pFormatCtx);
	avformat_free_context(pFormatCtx);
	LOGE("This is end test.");
	isPlaying=0;
	quit=0;
	return 0;
}
